<?php
namespace PsiFramework\Applications\AlloMediaUser\Classes\Actions;

import("Applications.AlloMediaPortal.Classes.Actions.AlloMediaUserAction");
import("Classes.Util.HTTP.AuthenticationManager");
import("Classes.Factory.DAOFactory");
import("Plugins.Shop.Classes.Model.Order");
import("Classes.Util.Object.Date");

use \PsiFramework\Applications\AlloMediaPortal\Classes\Actions\AlloMediaUserAction;
use \PsiFramework\Applications\AlloMediaPortal\Classes\Model\InformationPart;
use \PsiFramework\Classes\Util\HTTP\AuthenticationManager;
use \PsiFramework\Classes\Util\Manager\ApplicationManager;
use \PsiFramework\Classes\Util\Parameters\Action\ActionParameters;
use \PsiFramework\Classes\Util\Object\Date;
use \PsiFramework\Classes\Util\Object\ReferenceObject;
use \PsiFramework\Classes\Factory\DAOFactory;
use \PsiFramework\Plugins\Shop\Classes\Model\ItemCategory;
use \PsiFramework\Plugins\Shop\Classes\Model\Order;
use \PsiFramework\Plugins\Shop\Classes\Model\OrderItem;
use \PsiFramework\Plugins\Shop\Classes\Model\OrderItemLink;
use \PsiFramework\Plugins\Shop\Classes\Model\OrderItemLinkTax;
use \PsiFramework\Classes\Util\UI\LanguageManager;

/**
 * PsiFramework
 * Php Simple Framework
 *
 * @author Rémi San
 * @version beta
 */

/**
 * Classe d'action de l'index
 *
 * @package Actions.Pages
 */
class ShopAction extends AlloMediaUserAction
{

    /**
     * The constructor
     * 
     * @param ActionParameters $actionParameters the parameters
     * 
     * @return void
     */
    public function __construct(ActionParameters $actionParameters)
    {
        parent::__construct($actionParameters);
    }

    /**
     * Gets the item
     * 
     * @param ReferenceObject $refObject The reference object
     * @param InformationPart $part      The part
     * 
     * @return OrderItem
     */
    public static function getItem(ReferenceObject $refObject, /*InformationPart*/ $part=null)
    {
    	$itemDao = DAOFactory::getDAO('OrderItem');
    	$item = $itemDao->retrieveByReferenceObject($refObject);
    
    	if (is_null($item)) {
    		$item = new OrderItem(null, $refObject);
    		$itemDao->save($item);
    	}
    
    	if (is_null($item->getCategory()) && !is_null($part)) {
    
    		$themeCategoryName = $part->getTheme()->getName();
    		$categoryName
        		= $part->getProfile()->getName() .
        		' - ' .
        		$themeCategoryName;
    
    		$categoryDao = DAOFactory::getDAO('ItemCategory');
    		$category = $categoryDao->retrieveByName($categoryName);
    
    		if (is_null($category)) {
    
    			$themeCategory = $categoryDao->retrieveByName($themeCategoryName);
    
    			if (is_null($themeCategory)) {
    
    				$allThemeCategoryName = 'Theme';
    				$allThemeCategory = $categoryDao->retrieveByName($allThemeCategoryName);
    
    				if (is_null($allThemeCategory)) {
    					$allThemeCategory = new ItemCategory(null, $allThemeCategoryName);
    					$categoryDao->save($allThemeCategory);
    				}
    
    				$themeCategory = new ItemCategory(null, $themeCategoryName, null, $allThemeCategory);
    				$categoryDao->save($themeCategory);
    			}
    			$category = new ItemCategory(null, $categoryName, null, $themeCategory);
    			$categoryDao->save($category);
    		}
    		$item->setCategory($category);
    		$itemDao->save($item);
    	}
    
    	return $item;
    }
    
    /**
     * Add an item to the order
     * 
     * @param Order     $order    The order
     * @param OrderItem $item     The item
     * @param int       $quantity The quantity
     * 
     * @return void
     */
    public static function addItemToOrder(/*Order*/ $order, /*OrderItem*/ $item, /*int*/ $quantity)
    {
        $link = null;
        $items = $order->getItems();
        foreach ($items as $itemLink) {
        	$currItem = $itemLink->getItem();
        	if ($currItem->getId() == $item->getId()) {
        		$itemLink->setPrice(null);
        		$itemLink->setQuantity($quantity);
        		$link = $itemLink;
        		$item = $currItem;
        		break;
        	}
        }
        
        $orderItemLinkDao = DAOFactory::getDAO('OrderItemLink');
        $orderItemLinkTaxDao = DAOFactory::getDAO('OrderItemLinkTax');
        
        if (is_null($link)) {
        	$link = new OrderItemLink($order, $item, $quantity);
        	$orderItemLinkDao->save($link);
        	
        	$taxDao = DAOFactory::getDAO('Tax');
        	$jsonTaxes = ApplicationManager::getInstance()->getApplication()->getParameter('taxes');
        	$taxes = json_decode($jsonTaxes);
        	
        	$taxOrder = 1;
        	foreach ($taxes as $taxKey) {
            	$tax = $taxDao->retrieveByKey($taxKey);

            	$linktax = new OrderItemLinkTax($link, $tax, $taxOrder);
            	$orderItemLinkTaxDao->save($linktax);
            	
            	$link->addTax($linktax);
            	$taxOrder++;
        	}
        	$order->addItem($link);
        }
        
        $orderItemLinkDao->save($link);
    }
    
    /**
     * Function that returns the parameterized quantities with the discounts
     * 
     * @param boolean $checkSecurity check the security ?
     * 
     * @return array
     */
    public static function getQuantities(/*boolean*/ $checkSecurity=true)
    {
        $categoryDao = DAOFactory::getDAO('ItemCategory');
        $theme = $categoryDao->retrieveByName('Theme', false);
        
        $languageManager = LanguageManager::getInstance();
        
        $quantities = array();
        $paramQuantitiesJson = ApplicationManager::getInstance()->getApplication()->getParameter('shopQuantities');
        $paramQuantities = json_decode($paramQuantitiesJson);
        
        $defaultQuantity = ApplicationManager::getInstance()->getApplication()->getParameter('shopDefaultQuantity');
        
        $quantities = array();
        foreach ($paramQuantities as $quantity) {
            $suffix = '';
            if ($quantity == 1) {
                $suffix = $languageManager->getText('MONTH');
            } else {
                $suffix = $languageManager->getText('MONTHS');
            }
            $quantities[$quantity]
                = array(
                    'label'=>$quantity.' '.$suffix
                );
        }
        
        $discountDao = DAOFactory::getDAO('Discount');
        
        foreach ($quantities as $q=>$qa) {
        	$discounts = $discountDao->getDiscountsByCategoryQuantity($theme, $q, $checkSecurity);
        
        	$discountInfo = '';
        	$discount = null;
        	if (count($discounts)>0) {
        		$discountInfo = ' ('.$discounts[0]->getStringDiscountValue(self::getCurrency($checkSecurity)->getSymbol()).' '.$languageManager->getText('DISCOUNT_END').')';
        		$discount = $discounts[0];
        	}
        
        	$selectedQuantity = ($q==$defaultQuantity);
        	
        	$quantities[$q]['short-label'] = $qa['label'];
        	$quantities[$q]['label'] = $qa['label'].$discountInfo;
        	$quantities[$q]['discount'] = $discount;
        	$quantities[$q]['selected'] = $selectedQuantity;
        	
        }
        
        return $quantities;
    }
    
    /**
     * Retrieve the calculated order as an array
     * 
     * @param Order   $order             The order
     * @param boolean $recalculate       Recalculate the amounts ?
     * @param boolean $saveModifications Save the modifications after recalculating ?
     * @param boolean $validate          Validate the order ?
     * @param boolean $checkSecurity     Do the security checks ?
     * 
     * @return array
     */
    public static function getOrder(/*Order*/ $order, /*boolean*/ $recalculate=true, /*boolean*/ $saveModifications=false, /*boolean*/ $validate=false, /*boolean*/ $checkSecurity=true)
    {
        
        $quantities = ShopAction::getQuantities($checkSecurity);
        
        $orderItemLinkDao = DAOFactory::getDAO('OrderItemLink');
        $responseIdDao = DAOFactory::getDAO('ResponseId');
        
        $orderArray
            = array(
                'number'=>$order->getNumber(),
                'items'=>array()
            );
        
        $taxes = array();
        $total = 0;
        $realTotal = 0;
        $i = 0 ;
        foreach ($order->getItems() as $itemLink) {
            $itemArray = array();
            
        	$item = $itemLink->getItem();
        	$itemArray['id'] = $item->getId();
        	
        	$responseId = $item->getItem()->getObject(false, $checkSecurity);
        	$itemArray['item'] = $responseId;
        	
        	$quantity = $itemLink->getQuantity();
        	$itemArray['quantity'] = $quantity;
        	$quantityLabel = $quantity;
        	if (array_key_exists($quantity, $quantities)) {
        	    $quantityLabel = $quantities[$quantity]['short-label'];
        	}
        	$itemArray['quantityLabel'] = $quantityLabel;
        
        	$price = null;
        	$itemName = null;
        	$itemSubText = null;
        	if ($recalculate && !is_null($responseId)) {
            	$samplePart = new InformationPart();
            	$samplePart->setTheme($responseId->getTheme());
            	$samplePart->setProfile($responseId->getEntry()->getCategory()->getProfile());
            	$informationPartDao = DAOFactory::getDAO('InformationPart');
            	$part = $informationPartDao->retrieveByPk($samplePart->getId(), false, $checkSecurity);
            
            	$price = $part->getPrice();
            	$itemName = $responseId->getEntry()->toString() . ' - ' . $responseId->getTheme()->toString();
            	$itemSubText = '';
            	$sites = $responseId->getEntry()->getCategory()->getSites();
            	if (!is_null($sites) && count($sites)>0) {
            	    foreach ($sites as $site) {
            	        if (!isNullOrEmptyString($itemSubText)) {
            	            $itemSubText .= ', ';
            	        }
            	        $itemSubText .= $site->getSite()->getName();
            	    }
            	}
        	} else {
        	    $price = $itemLink->getPrice();
        	    $itemName = $itemLink->getItemName();
        	    $itemSubText = $itemLink->getItemSubtext();
        	}
        	$itemArray['price'] = $price;
        	$itemArray['itemName'] = $itemName;
        	$itemArray['itemSubtext'] = $itemSubText;
        
        	$subTotal = $quantity*$price;
        	$total += $subTotal;
        	$itemArray['subTotal'] = $subTotal;
        	
        	$realSubTotal = null;
        	$discountValue = null;
        	
        	if ($recalculate) {
        	    $realSubTotal = $subTotal;
            	if (!is_null($quantities[$quantity]['discount'])) {
            		$discount = $quantities[$quantity]['discount'];
            		if ($discount->isPercentage()) {
            		    $discountValue = $subTotal*($discount->getValue()/100);
            		} else {
            			$discountValue = $discount->getValue();
            		}
            		$realSubTotal = $subTotal-$discountValue;
            	}
        	} else {
        	    $discountValue = $itemLink->getDiscount();
        	    $realSubTotal = $itemLink->getTotal();
        	}
        	
        	$itemArray['discountValue'] = $discountValue;
        	$itemArray['realSubTotal'] = $realSubTotal;
        
        	$taxesArray = array();
        	$taxesLinkDao = DAOFactory::getDAO('OrderItemLinkTax');
        	$taxesLinks = $itemLink->getTaxes();
        	foreach ($taxesLinks as $taxesLink) {
        		$taxesLink->setLink($itemLink);
        		$tax = $taxesLink->getTax();
        		$taxName = $tax->getName();
        		if (!array_key_exists($taxName, $taxes)) {
        			$taxes[$taxName] = array('tax'=>$tax, 'value'=>null, 'total'=>null);
        		}
        		
        		$taxValue = null;
        		$taxTotal = null;
        		
        		if ($recalculate) {
        		    $taxValue = $tax->getValue();
        		    if ($tax->isPercentage()) {
        		        $taxTotal = $realSubTotal * ($taxValue/100);
        		    } else {
        		        $taxTotal = $taxValue;
        		    }
        		} else {
        		    $taxValue = $taxesLink->getValue();
        		    $taxTotal = $taxesLink->getTotal();
        		}
        		$taxes[$taxName]['value'] = $taxValue ;
        		$taxes[$taxName]['total'] += $taxTotal ;
        		
        		$taxesArray[] = array('tax'=>$tax, 'value'=>$taxValue, 'total'=>$taxTotal);
        		
        		if ($saveModifications) {
        		    $taxesLink->setValue($taxValue);
        		    $taxesLink->setTotal($taxTotal);
        		    $taxesLinkDao->save($taxesLink, true, $checkSecurity);
        		}
        	}
        	$itemArray['taxes'] = $taxesArray;
        
        	$realTotal += $realSubTotal;
        
        	$date = null;
        	if (!is_null($responseId)) {
        	    $date = $responseId->getExpirationDate();
        	}
        	if (is_null($date) || $date->before(Date::now())) {
        		$date = Date::now();
        	}
        	$date->addMonths($quantity);
        
        	if ($validate && !$order->isPaid()) {
            	$responseId->setPaid(true);
            	$responseId->setExpirationDate($date);
            	$responseIdDao->save($responseId, true, $checkSecurity);
        	}
        	
        	if ($saveModifications) {
        	    $itemLink->setPrice($price);
        	    $itemLink->setDiscount($discountValue);
        	    $itemLink->setTotal($realSubTotal);
        	    $itemLink->setItemName($itemName);
        	    $itemLink->setItemSubtext($itemSubText);
            	$orderItemLinkDao->save($itemLink, true, $checkSecurity);
        	}
        	
        	$orderArray['items'][$i] = $itemArray;
        	$i++;
        }
        
        $orderArray['total'] = $total;
        $orderArray['realTotal'] = $realTotal;
        
        $totalTaxes = 0;
        foreach ($taxes as $taxName=>$taxValue) {
        	$totalTaxes += $taxValue['total'];
        }
        $orderArray['taxes'] = $taxes;
        $orderArray['totalTaxes'] = $totalTaxes;
        
        $paymentTotal = $realTotal+$totalTaxes;
        $orderArray['paymentTotal'] = $paymentTotal;
        
        $date = Date::now();
        if (!$recalculate) {
            $date = $order->getDate();
        }
        $orderArray['date'] = $date;
        
        $orderArray['mean'] = $order->getMeanOfPayment();
        
        $customerName = null;
        $customerAddress = null;
        $customerZipCode = null;
        $customerCity = null;
        
        $user = $order->getUser();
        DAOFactory::getDAO('User')->refresh($user);
        if ($recalculate && !is_null($user)) {
            $customerName = $user->getFirstName() . ' ' . $user->getSurName();
            $customerAddress = $user->getAddress();
            $customerZipCode = $user->getZipCode();
            $customerCity = $user->getCityName();
        } else {
            $customerName = $order->getCustomerName();
            $customerAddress = $order->getCustomerAddress();
            $customerZipCode = $order->getCustomerZip();
            $customerCity = $order->getCustomerCity();
        }
        
        $orderArray['customerName'] = $customerName;
        $orderArray['customerAddress'] = $customerAddress;
        $orderArray['customerZipCode'] = $customerZipCode;
        $orderArray['customerCity'] = $customerCity;
        
        if ($saveModifications) {
            $order->setTotal($paymentTotal);
            $order->setCustomerName($customerName);
            $order->setCustomerAddress($customerAddress);
            $order->setCustomerZip($customerZipCode);
            $order->setCustomerCity($customerCity);
            if ($validate) {
                $order->setPaid(true);
                $order->setDate($date);
            }
            $orderDao = DAOFactory::getDAO('Order');
            $orderDao->save($order, true, $checkSecurity);
        }
        
        return $orderArray;
    }
    
    /**
     * The main function of the method which is called every time
     * an action is created by the front controller.
     *
     * @return void
     */
    public function execute()
    {
        parent::execute();

        $orderDao = DAOFactory::getDAO('Order');
        $order = $orderDao->retrieveActiveOrderByUser($this->_user, false);
        
        if (is_null($order)) {
        	$order = new Order(null, uniqid(), Date::now(), $this->_user);
        	$order->setCurrency($this->_response->getAttribute('Currency'));
        	$orderDao->save($order);
        }
        
        $this->_response->setAttribute('order', $order);
        
        $this->_response->setAttribute('quantities', self::getQuantities());
    }
}
